package com.neuronbit.businessflow.intellij.psi;

import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.changeSignature.CallReferenceUsageInfo;
import com.intellij.refactoring.changeSignature.ChangeInfo;
import com.intellij.refactoring.changeSignature.PsiCallReference;
import com.intellij.refactoring.rename.ResolveSnapshotProvider;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.containers.MultiMap;
import com.neuronbit.businessflow.intellij.lang.PsiJavaMethodCall;
import org.jetbrains.annotations.NotNull;

import java.util.List;

/**
 * The type Change signature usage processor.
 */
public class ChangeSignatureUsageProcessor implements com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor {
    @Override
    public UsageInfo[] findUsages(ChangeInfo changeInfo) {
        return new UsageInfo[0];
    }

    @Override
    public MultiMap<PsiElement, String> findConflicts(ChangeInfo changeInfo, Ref<UsageInfo[]> ref) {
        return new MultiMap<>(0);
    }

    @Override
    public boolean processUsage(ChangeInfo changeInfo, UsageInfo usageInfo, boolean beforeMethodChange, UsageInfo[] usageInfos) {
        if (changeInfo.getLanguage() == JavaLanguage.INSTANCE && usageInfo instanceof CallReferenceUsageInfo callReferenceUsageInfo) {
            PsiCallReference reference = callReferenceUsageInfo.getReference();
            if (reference != null) {
                PsiJavaMethodCall javaMethodCall = (PsiJavaMethodCall) reference.getElement();
                /*
                 * 这里有两种模式，一种是整个 call 进行替换，另外一种是精确替换
                 * 1. 整个替换，整个文本的替换相对麻烦，需要基于原有文本进行替换，但是文本转换为 psielement 就比较简单且可复用
                 * 2. 精确替换，文本的组织相对简单，不用管原来是什么样子，但是文本转 psielement 就比较麻烦一些，需要针对不同类型的 psielement 写不同的转换逻辑
                 * 如果是用方案 1，又何必使用 psielement 的修改机制呢？唯一的好处就是不用直接修改文件而可以让文件内容发生改变？
                 * 整个问题也是一个粒度的问题
                 * 方案 1，如果语法发生的变更，这里的替换逻辑有可能需要跟着修改，不过方案 2 也有类似的问题，只是修改的点不一样。
                 */
                if (changeInfo.isNameChanged()) {
                    javaMethodCall.setMethod(changeInfo.getNewName());
                }
                if (changeInfo.isParameterNamesChanged() || changeInfo.isParameterTypesChanged() || changeInfo.isParameterSetOrOrderChanged()) {
                    javaMethodCall.setParameters(changeInfo.getNewParameters());
                }
                if (changeInfo.isReturnTypeChanged()) {
                    PsiType returnType = ((PsiMethod) changeInfo.getMethod()).getReturnType();
                    javaMethodCall.setReturnType(returnType);
                }

            }

            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean processPrimaryMethod(ChangeInfo changeInfo) {
        return false;
    }

    @Override
    public boolean shouldPreviewUsages(ChangeInfo changeInfo, UsageInfo[] usageInfos) {
        return false;
    }

    @Override
    public boolean setupDefaultValues(ChangeInfo changeInfo, Ref<UsageInfo[]> ref, Project project) {
        return true;
    }

    @Override
    public void registerConflictResolvers(List<? super ResolveSnapshotProvider.ResolveSnapshot> list, @NotNull ResolveSnapshotProvider resolveSnapshotProvider, UsageInfo[] usageInfos, ChangeInfo changeInfo) {
        System.out.println("ss");
    }
}
